﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;

namespace General
{
    /// <summary>
    /// Hilft einfach schnelle informative Ausgaben in der Konsole zu machen.
    /// </summary>
    public static class ConsolePrinter
    {
        #region Imports
        [DllImport("kernel32.dll")]
        static extern bool AllocConsole();

        [DllImport("kernel32.dll")]
        static extern bool FreeConsole();
        #endregion Imports

        #region Attribute
        private static object writeLock = new object();
        private static bool consoleAllocated = false;
        #endregion Attribute

        #region Methoden
        /// <summary>
        /// Gibt einen Exceptionstack aus.
        /// </summary>
        /// <param name="e">Die Exception.</param>
        public static void PrintExceptionStack(Exception e)
        {
            lock (writeLock)
            {
                int i = 1;
                WriteLine(e.GetType().ToString() + ": " + e.Message, ConsoleColor.Red, ConsoleColor.Black);
                if (e.StackTrace != null) WriteLine(fillString(">", i) + e.StackTrace.Replace("\n", "\n" + fillString(">", i) + " ").Replace("   ", " "), ConsoleColor.Gray, ConsoleColor.Black);
                Exception ie = e.InnerException;
                while (ie != null)
                {
                    WriteLine(fillString(" ", i) + "" + ie.GetType().ToString() + ": " + ie.Message, ConsoleColor.White, ConsoleColor.Black);
                    if (e.StackTrace != null) WriteLine(fillString(">", i) + e.StackTrace.Replace("\n", "\n" + fillString(">", i) + " ").Replace("   ", " "), ConsoleColor.Gray, ConsoleColor.Black);
                    ie = ie.InnerException;
                    i++;
                }
            }
        }

        /// <summary>
        /// Schreibt eine Zeile in die Konsole.
        /// </summary>
        /// <param name="s">Die Zeichenkette.</param>
        public static void WriteLine(string s)
        {
            lock (writeLock)
            {
                Console.WriteLine(s);
            }
        }

        /// <summary>
        /// Schreibt eine Zeile in die Konsole.
        /// </summary>
        /// <param name="s">Die Zeichenkette.</param>
        /// <param name="foregroundColor">Die Vorderundfarbe.</param>
        /// <param name="backgroundColor">Die Hintergrundfarbe.</param>
        public static void WriteLine(string s, ConsoleColor foregroundColor, ConsoleColor backgroundColor)
        {
            lock (writeLock)
            {
                ConsoleColor oldForegroundColor = Console.ForegroundColor;
                ConsoleColor oldBackgroundColor = Console.BackgroundColor;
                Console.ForegroundColor = foregroundColor;
                Console.BackgroundColor = backgroundColor;
                Console.WriteLine(s);
                Console.ForegroundColor = oldForegroundColor;
                Console.BackgroundColor = oldBackgroundColor;
            }
        }

        /// <summary>
        /// Schreibt in die Konsole.
        /// </summary>
        /// <param name="s">Die Zeichenkette.</param>
        public static void Write(string s)
        {
            lock (writeLock)
            {
                Console.Write(s);
            }
        }

        /// <summary>
        /// Schreibt in die Konsole.
        /// </summary>
        /// <param name="s">Die Zeichenkette.</param>
        /// <param name="foregroundColor">Die Vorderundfarbe.</param>
        /// <param name="backgroundColor">Die Hintergrundfarbe.</param>
        public static void Write(string s, ConsoleColor foregroundColor, ConsoleColor backgroundColor)
        {
            lock (writeLock)
            {
                ConsoleColor oldForegroundColor = Console.ForegroundColor;
                ConsoleColor oldBackgroundColor = Console.BackgroundColor;
                Console.ForegroundColor = foregroundColor;
                Console.BackgroundColor = backgroundColor;
                Console.Write(s);
                Console.ForegroundColor = oldForegroundColor;
                Console.BackgroundColor = oldBackgroundColor;
            }
        }

        /// <summary>
        /// Öffnet die Konsole.
        /// </summary>
        /// <returns>Indikator ob eine Konsole geöffnet ist.</returns>
        public static bool Open()
        {
            if (!consoleAllocated && Environment.OSVersion.Platform == PlatformID.Win32NT) consoleAllocated = AllocConsole();
            return consoleAllocated;
        }

        /// <summary>
        /// Schließt die Konsole.
        /// </summary>
        public static void Close()
        {
            if (consoleAllocated) FreeConsole();
            consoleAllocated = false;
        }

        /// <summary>
        /// Gibt eine Zeichenkette zurück, die mit einer spezifischen Anzahl eines spezifischen Zeichens gefüllt ist.
        /// </summary>
        /// <param name="s">Das Zeichen.</param>
        /// <param name="c">Die Anzahl.</param>
        /// <returns>Die Zeichenkette.</returns>
        private static string fillString(string s, int c)
        {
            string output = "";
            for (int i = 0; i < c; i++) output += s;
            return output;
        }
        #endregion Methoden
    }
}
